#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include "bmock.hpp"
#include "bmock_util.hpp"
#include "bmock_control_tools_mock.hpp"
#include <boost/bind.hpp>

class testclass2 {
public:
	testclass2 ():res(0){}

	void testf () {res = 20;}
	void testf1 () {res = 20;}
	int dynf() {res = 30;return res;}
	int cynf() {res = 30;return res;}
	
	int res;
};


typedef int (testclass2::*f_ptr)();
typedef void (testclass2::*tc_ptr)();

static void g1(tc_ptr f) {
	MOCK_VOID(1, (MEMBER_CLBK(f)));
}
static void g2(f_ptr f) {
	MOCK_VOID(1, (MEMBER_CLBK(f)));
}
static void g3(f_ptr& f) {
	MOCK_VOID(1, (OUT(f)));
}
static void g4(f_ptr* f) {
	MOCK_VOID(1, (OUT(f)));
}
static f_ptr g5() {
	MOCK(0,());
	return NULL;
}
static void g6(tc_ptr f) {
	MOCK_VOID(1, (IN_PTR(f)));
}
static void g7(f_ptr f) {
	MOCK_VOID(1, (IN_PTR(f)));
}

static int					(testclass2::*m)()	=NULL;
static int					(testclass2::*n)()	=&testclass2::dynf;



struct bfixture2 { 
	bfixture2() {
		BMOCK_CREATE_MOCK(*);
	}
};

BMOCK_TEST (bfixture2, test_void_member_function_memberclbk_arg) {
	BMOCK_EXPECT(g1(&testclass2::testf));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(g1(&testclass2::testf));
	BMOCK_VERIFY;
}

BOOST_AUTO_TEST_CASE(test_void_member_function_memberclbk_arg_not_same2) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	tc_ptr f1 = &testclass2::testf1;
	tc_ptr f = &testclass2::testf;
	std::string sf1=BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(bmock::pointer_reinterpret<void*>(f1));
	std::string sf=BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(bmock::pointer_reinterpret<void*>(f));

	__BMOCK_EXPECT_RETURN_C(c,true,t->check_equal(sf,sf1,bmock::message(bmock::ARG_VALUE,"f"),bmock::location(__FILE__,__LINE__+5)));
	__BMOCK_EXPECT_C(c,t->abort(bmock::location(__FILE__,__LINE__+4)));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);__BMOCK_CREATE_MOCK_C((&c1),*);
		BOOST_CHECK_NO_THROW(__BMOCK_EXPECT_C(c1,g1(&testclass2::testf)));
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(g1(&testclass2::testf1));
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BMOCK_TEST (bfixture2, test_member_function_memberclbk_arg) {
	BMOCK_EXPECT(g2(&testclass2::dynf));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(g2(n));
	BMOCK_VERIFY;
}
BMOCK_TEST (bfixture2, test_void_member_function_ptr_out_reference_arg) {
	m = NULL;
	BMOCK_EXPECT(g3(n));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(g3(m));
	BMOCK_VERIFY;
	BOOST_CHECK(n==m);
}
BMOCK_TEST (bfixture2, test_void_member_function_ptr_out_double_ptr_arg) {
	m = NULL;

	BMOCK_EXPECT(g4(&n));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(g4(&m));
	BMOCK_VERIFY;
	BOOST_CHECK(n==m);
}

BMOCK_TEST (bfixture2, test_return_member_function_pointer) {
	m = NULL;

	BMOCK_EXPECT_RETURN(n, g5());
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(m = g5());
	BMOCK_VERIFY;
	BOOST_CHECK(n==m);
}

BMOCK_TEST (bfixture2, test_void_member_function_ptr_in_arg) {
	BMOCK_EXPECT(g6(&testclass2::testf));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(g6(&testclass2::testf));
	BMOCK_VERIFY;
}


BOOST_AUTO_TEST_CASE(test_void_member_function_ptr_in_arg_not_same2) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	tc_ptr f1 = &testclass2::testf1;
	tc_ptr f = &testclass2::testf;
	std::string sf1=BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(bmock::pointer_reinterpret<void*>(f1));
	std::string sf=BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(bmock::pointer_reinterpret<void*>(f));

	__BMOCK_EXPECT_RETURN_C(c,true,t->check_equal(sf,sf1,bmock::message(bmock::ARG_VALUE,"f"),bmock::location(__FILE__,__LINE__+5)));
	__BMOCK_EXPECT_C(c,t->abort(bmock::location(__FILE__,__LINE__+4)));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);__BMOCK_CREATE_MOCK_C((&c1),*);
		BOOST_CHECK_NO_THROW(__BMOCK_EXPECT_C(c1,g6(&testclass2::testf)));
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(g6(&testclass2::testf1));
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BMOCK_TEST (bfixture2, test_member_function_ptr_in_arg) {
	BMOCK_EXPECT(g7(&testclass2::dynf));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(g7(n));
	BMOCK_VERIFY;
}
